#define RUNTIME_DBG_LVL			0
#include <dbg/ptest.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <metalc/base/mtls.h>
#include <metalc/mlos/tsysmalloc.h>
#include <pthreadalt.h>

/* sysmalloc申请的大小并非准确值，因此释放的时候要降阶防止内存不够用 */
#define TCACHE_UPPER_NOT_EXACT_SIZE
// #include <unix/page_alloc_os.h>

#include "apds_common.h"


/* 定义mmap heap */
// DEF_MMAPHEAP_MLAYER(mmap_normal, 2 * 1024 * 1024, SIZE_1G, SIZE_64G, 1, 0)

/* 定义tcache */
#include <metalc/mlayer/tcache.h>
DEF_CLS_TC(tc, 3, 14)
DEF_TCACHE_MLAYER(tcache, 3, 14, tc, SIZE_4M, 0, 2, mlcc_palloc)

#include <metalc/mladt/bulk.h>
/* 组合 */
COMPOSE_MLAYER(test_tcache, tcache, bulk, tsysmalloc)

/* 定义tls */
DEF_MTLS_PTHREAD(GET_MLAYER_OBJNR(test_tcache), 4096, mlcc_palloc, mp_coreid)

/* 定义初始化过程 */
#include <pthreadalt/pthreadalt_init.h>
DEF_PTHREADALT_INIT
DEF_SYSINIT(mtls, testnode, test_tcache)
DEF_CFLOWFIN(mtls)
DEF_CFLOWINIT(mtls, test_tcache)
DEF_SYSFIN(__omega)

/* 测试 */

#define TEST_MAXTHREADS	(24)
#define TEST_NR		(1000000)

#define TEST_MINSIZE	(1)
#define TEST_MAXSIZE	(256)
#define TEST_SET	(1)
#define TEST_ALLOC	test_tcache_alloc
#define TEST_FREE	test_tcache_free
#define TEST_SIZEOF	test_tcache_sizeof
// static void *bench_tcache(void *args){
// 	PARAM_USED(args);
// 	mreq_t req;
// 	for (word_t idx = 0; idx < TEST_NR; idx++){
// 		size_t rqsize = TEST_MINSIZE + hash(idx + rdcnt_relax()) % (TEST_MAXSIZE - TEST_MINSIZE);
// 		mreq_setalloc(&req, rqsize, 0);
		
// 		void *mem = TEST_ALLOC(&req);
// 		assert(mem);
		
// 		uvoid *umem = req.ptr;
// 		assert(umem);
// 		PARAM_USED(umem);
// 		assert(umem - mem == sizeof(cobj_t));
// 		size_t size = TEST_SIZEOF(&req);
// 		assert(size >= rqsize);
		
// 		size_t usize = req.usize;
// 		assert(usize >= rqsize);
// 		assert(size - usize == sizeof(cobj_t));
// 		assert(req.ptr == mem);
// 		req.size = size;
		
// 		if (TEST_SET) {
// 			__memset(umem, 0xff, rqsize);
// 			INFO("memset [%p - %p]\n", umem, umem + usize);
// 		}
// 		/* printf("[set %lx]") */
// 		bool_t s = TEST_FREE(&req);
// 		assert(s == TRUE);
// 	}
// 	return NULL;
// }

static void *bench_tcache(void *args){
	PARAM_USED(args);
	mreq_t req;
	for (word_t idx = 0; idx < TEST_NR; idx++){
		size_t rqsize = TEST_MINSIZE + hash(idx + rdcnt_relax()) % (TEST_MAXSIZE - TEST_MINSIZE);
		mreq_setalloc(&req, rqsize, 0);
		uvoid *umem = TEST_ALLOC(&req);
		void *mem = req.ptr;
		// assert(umem);
		
		assert(umem);
		req.ptr = umem;
		size_t size = TEST_SIZEOF(&req);
		assert(size >= rqsize);
		PARAM_USED(umem, mem, size);
		if (TEST_SET) {
			__memset(umem, 0xff, rqsize);
			// INFO("memset [%p - %p]\n", umem, umem + usize);
		}
		req.nr = 1;
		TEST_FREE(&req);
	}
	return NULL;
}
PERF_PARALLEL_FUNC_THREADNR(bench_tcache, TEST_NR * 2, TEST_MAXTHREADS)

void test_tcache_basic(){
	mreq_t req;
	void *mem;
	mreq_setalloc(&req, 16, 0);
	mem = test_tcache_alloc(&req);

	req.ptr = mem;
	size_t sz = test_tcache_sizeof(&req);
	assert(sz >= 16);

	bool_t s = test_tcache_free(&req);
	assert(s == TRUE);

}
static void test_tcache_end(){
	dbg_printf("tcache bench ok\n");
}
/* perf测试 */
int main(){
	test_tcache_basic();
	dbg_printf("now bench tcache\n");
	PERF_PARALLEL_RUN(bench_tcache);
	test_tcache_end();
	return 0;
}